package com.ganyu.service.impl;

import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ganyu.component.RedisCache;
import com.ganyu.domain.LoginUser;
import com.ganyu.domain.ResponseResult;

import com.ganyu.domain.entity.Menu;
import com.ganyu.domain.entity.User;

import com.ganyu.domain.vo.AdminUserInfoVo;
import com.ganyu.domain.vo.MenuVo;
import com.ganyu.domain.vo.RoutersVo;
import com.ganyu.domain.vo.UserInfoVo;
import com.ganyu.exception.SystemException;

import com.ganyu.mapper.*;
import com.ganyu.service.AdminLoginService;
import com.ganyu.utils.BeanCopyUtils;
import com.ganyu.utils.JwtUtil;
import com.ganyu.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;


import java.util.*;

import static com.ganyu.enums.AppHttpCodeEnum.*;

/**
 * DATA: 2022/9/28
 * Author: 晨夕
 */
@Service
public class AdminLoginServiceImpl implements AdminLoginService {
    /**
     * 用户登录
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public ResponseResult<User> login(User user) {
        //1.用户未输入用户名或密码，提醒用户
        if(StringUtils.isEmpty(user.getUserName())){
            throw new SystemException(REQUIRE_USERNAME);
        }
        if(StringUtils.isEmpty(user.getPassword())){
            throw new SystemException(REQUIRE_PASSWORD);
        }
        //用户不存在，提醒
        User user1 = userMapper.selectUserName(user.getUserName());
        if(ObjectUtils.isEmpty(user1)){
            throw new SystemException(USERNAME_ERROR);
        }
        //密码输入有误，提醒
        String password = userMapper.selectPassword(user.getUserName());
        boolean matches = passwordEncoder.matches(user.getPassword(), password);
        if(!matches){
            throw new SystemException(PASSWORD_ERROR);
        }
        //2.调用ProviderManager的方法进行认证 如果认证通过生成jwt
        //2.1 进行认证
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        //2.2判断是否认证成功
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("用户不存在或密码错误");
        }
        //2.3 认证成功后，获取authenticate中的用户主体信息
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        //2.4 获取用户id，生成jwt
        String userId = loginUser.getUser().getId().toString();
        String token = JwtUtil.createJWT(userId);
        //3.把用户信息存入redis中
        redisCache.setCacheObject("login:" + userId ,loginUser);
        Map<String,String> map = new HashMap<>();
        map.put("token", token);
        return ResponseResult.okResult(map);
    }

    /**
     * 获取用户菜单、角色名、个人信息
     */
    @Override
    public ResponseResult<AdminUserInfoVo> getUserInfo() {
        //获取用户id，根据用户id从数据库中查菜单
        Long userId = SecurityUtils.getUserId();
        //获取用户信息
        User user = SecurityUtils.getLoginUser().getUser();
        UserInfoVo userInfoVo = BeanCopyUtils.copyBean(user, UserInfoVo.class);
        //1. 先根据user_id获取role_id
        Long roleId = userRoleMapper.getRoleId(userId);
        //2.根据role_id获取role_key
        List<String> roleKeyById = roleMapper.getRoleKeyById(roleId);
        //如果userId = 1L，permissions中需要有所有菜单类型为C或者F的，状态为正常的，未被删除的权限
        if(SecurityUtils.isAdmin()){
            List<String> permsList = menuMapper.getPermsList();
            AdminUserInfoVo adminUserInfoVo = new AdminUserInfoVo(permsList, roleKeyById, userInfoVo);
            return ResponseResult.okResult(adminUserInfoVo);
        }
        //3. 根据role_id获取menu_id
        List<Long> menuId = roleMenuMapper.getMenuId(roleId);
        ArrayList<String> perms = new ArrayList<>();
        //4. 根据menu_id获取perms
        for(Long id : menuId){
            String perById = menuMapper.getPerById(id);
            perms.add(perById);
        }
        AdminUserInfoVo adminUserInfoVo = new AdminUserInfoVo(perms, roleKeyById, userInfoVo);
        return ResponseResult.okResult(adminUserInfoVo);
    }

    /**
     * 获取菜单
     */
    @Override
    public ResponseResult<RoutersVo> getRouters() {
        //获取userId
        Long userId = SecurityUtils.getUserId();
        //1. 先根据user_id获取role_id
        Long roleId = userRoleMapper.getRoleId(userId);
        //2. 如果用户id为1代表管理员，menus中需要有所有菜单类型为C或者M的，状态为正常的，未被删除的权限
        if(SecurityUtils.isAdmin()){
            //根菜单
            List<Menu> menu = menuMapper.getMenuType(0L);
            List<MenuVo> menuVos = BeanCopyUtils.copyBeanList(menu, MenuVo.class);
            //子菜单
            for(MenuVo menuVo : menuVos){
                List<Menu> children = menuMapper.getChildrens(menuVo.getId());
                List<MenuVo> menuVos1 = BeanCopyUtils.copyBeanList(children, MenuVo.class);
                menuVo.setChildren(menuVos1);
            }
            RoutersVo routersVo = new RoutersVo(menuVos);
            return ResponseResult.okResult(routersVo);
        }
        //3. 根据role_id获取menu_id
        List<Long> menuId = roleMenuMapper.getMenuId(roleId);
        ArrayList<MenuVo> menuVoList2 = new ArrayList<>();
        //4. 根据menu_id获取perms
        for(Long id : menuId){
            //获取parent_id为0，根菜单
            Menu parentId = menuMapper.getParentId(id);
            if(!ObjectUtils.isEmpty(parentId)){
                MenuVo menuVo = BeanCopyUtils.copyBean(parentId, MenuVo.class);
                menuVoList2.add(menuVo);
                //子菜单
                List<Menu> children = menuMapper.getChildren(id);
                List<MenuVo> menuVos = BeanCopyUtils.copyBeanList(children, MenuVo.class);
                menuVo.setChildren(menuVos);
            }
        }
        RoutersVo routersVo = new RoutersVo(menuVoList2);
        return ResponseResult.okResult(routersVo);
    }

    //用户退出
    @Override
    public ResponseResult logout() {
        //获取用户id
        Long userId = SecurityUtils.getUserId();
        String id = userId.toString();
        if(id == null || id.isEmpty()){
            throw new SystemException(NEED_LOGIN);
        }
        //根据用户id从redis中删除数据
        redisCache.deleteObject("login:" + id);
        return ResponseResult.okResult();
    }
}
